package org.study.redis.search.boot.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.*;

import java.nio.charset.StandardCharsets;

/**
 * Redis 配置类。
 * <p>
 * StringRedisTemplate 与 RedisTemple 的区别：
 * 1、StringRedisTemplate 继承自 RedisTemple
 * 2、数据不共通，即：StringRedisTemplate 只能管理 StringRedisTemplate 的数据，RedisTemplate 只能管理 RedisTemplate 的数据
 * 3、spring-boot-starter-data-redis 默认的序列化方式有两种：String 序列化策略、JDK 序列化策略
 * StringRedisTemplate 默认采用的是 String 序列化策略，保存的 key、value 都是采用该策略序列化并保存的；
 * RedisTemplate 默认采用的是 JDK 序列化策略，保存的 key、value 都是采用此策略序列化并保存的
 *
 * @author Administrator
 * @date 2021-06-02
 */
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // Jdk 序列化器
        RedisSerializer jdkSerializationRedisSerializer = this.jdkSerializationRedisSerializer();
        // String 序列化器
        StringRedisSerializer stringRedisSerializer = this.stringRedisSerializer();
        // Jackson 序列化器
        RedisSerializer jackson2JsonRedisSerializer = this.jackson2JsonRedisSerializer();
        // FastJson 序列化器
        RedisSerializer fastJson2JsonRedisSerializer = this.fastJson2JsonRedisSerializer();
        // key 采用 String 的序列化方式，默认采用的是 JDK 序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        // value 采用 jackson 的序列化方式，默认采用的是 JDK 序列化方式
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplates(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate stringRedisTemplates = new StringRedisTemplate();
        stringRedisTemplates.setConnectionFactory(redisConnectionFactory);
        // Jdk 序列化器
        RedisSerializer jdkSerializationRedisSerializer = this.jdkSerializationRedisSerializer();
        // String 序列化器
        StringRedisSerializer stringRedisSerializer = this.stringRedisSerializer();
        // Jackson 序列化器
        RedisSerializer jackson2JsonRedisSerializer = this.jackson2JsonRedisSerializer();
        // FastJson 序列化器
        RedisSerializer fastJson2JsonRedisSerializer = this.fastJson2JsonRedisSerializer();
        // key 采用 String 的序列化方式，默认采用的是 JDK 序列化方式
        stringRedisTemplates.setKeySerializer(stringRedisSerializer);
        stringRedisTemplates.setHashKeySerializer(stringRedisSerializer);
        // value 采用 jackson 的序列化方式，默认采用的是 JDK 序列化方式
        stringRedisTemplates.setValueSerializer(jackson2JsonRedisSerializer);
        stringRedisTemplates.setHashValueSerializer(jackson2JsonRedisSerializer);
        stringRedisTemplates.afterPropertiesSet();
        return stringRedisTemplates;
    }

    /**
     * 配置 Jdk 序列化器
     */
    private RedisSerializer jdkSerializationRedisSerializer() {
        JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
        return jdkSerializationRedisSerializer;
    }

    /**
     * 配置 String 序列化器
     */
    private StringRedisSerializer stringRedisSerializer() {
        // StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(StandardCharsets.UTF_8);
        return stringRedisSerializer;
    }

    /**
     * 配置 Jackson 序列化器
     */
    private RedisSerializer jackson2JsonRedisSerializer() {
        // 配置对象映射器
        ObjectMapper objectMapper = new ObjectMapper();
        // 指定要序列化的域，field，get和set，以及修饰符范围。ANY指包括private和public修饰符范围
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入类型，类的信息也将添加到json中，这样才可以根据类名反序列化
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
        return jackson2JsonRedisSerializer;
    }

    /**
     * 配置 FastJson 序列化器
     */
    private RedisSerializer fastJson2JsonRedisSerializer() {
        FastJson2JsonRedisSerializer fastJson2JsonRedisSerializer = new FastJson2JsonRedisSerializer(Object.class);
        return fastJson2JsonRedisSerializer;
    }
}
